import type { 不可能, 是, 否, 空 } from './utils'
import type { 零, 一, 二, 三, 四, 五, 六, 七, 八, 九 } from './integer'
import type { 将, 士, 象, 马, 车, 炮, 兵 } from './kind'
import type { 红色, 黑色 } from './color'
import type { 棋子, 构造棋子 } from './chess'
import type {
  棋子坐标,
  构造棋子坐标,
  相同位置,
  左邻位,
  右邻位,
  上邻位,
  下邻位,
} from './position'
import type { 将可以放在这里吗 } from './chesses/general'
import type { 士可以放在这里吗 } from './chesses/guard'
import type { 象可以放在这里吗 } from './chesses/elephant'
import type { 马可以放在这里吗 } from './chesses/horse'
import type { 车可以放在这里吗 } from './chesses/chariot'
import type { 炮可以放在这里吗 } from './chesses/cannon'
import type { 兵可以放在这里吗 } from './chesses/soldier'
import type {
  棋局,
  默认棋局,
  获取棋局某位置的棋子,
  将棋局某位置替换为指定棋子,
  该位置没有棋子,
  该位置有棋子,
  在一条直线上并且中间没有棋子,
  在一条直线上并且中间只有一个棋子,
} from './situation'
import type { 渲染棋局 } from './render'

export type 棋子可以放在这里吗<某个棋子, 位置> = 某个棋子 extends 棋子
  ? 某个棋子['种类'] extends 将
    ? 将可以放在这里吗<某个棋子['颜色'], 位置>
    : 某个棋子['种类'] extends 士
    ? 士可以放在这里吗<某个棋子['颜色'], 位置>
    : 某个棋子['种类'] extends 象
    ? 象可以放在这里吗<某个棋子['颜色'], 位置>
    : 某个棋子['种类'] extends 马
    ? 马可以放在这里吗<某个棋子['颜色'], 位置>
    : 某个棋子['种类'] extends 车
    ? 车可以放在这里吗<某个棋子['颜色'], 位置>
    : 某个棋子['种类'] extends 炮
    ? 炮可以放在这里吗<某个棋子['颜色'], 位置>
    : 某个棋子['种类'] extends 兵
    ? 兵可以放在这里吗<某个棋子['颜色'], 位置>
    : 不可能
  : 不可能

/**
 * 将只能上下左右移动
 */
type 将可以去那里吗<
  起始位置 extends 棋子坐标,
  目标位置 extends 棋子坐标
> = 是 extends 相同位置<左邻位<起始位置>, 目标位置>
  ? 是
  : 是 extends 相同位置<右邻位<起始位置>, 目标位置>
  ? 是
  : 是 extends 相同位置<上邻位<起始位置>, 目标位置>
  ? 是
  : 是 extends 相同位置<下邻位<起始位置>, 目标位置>
  ? 是
  : 否

/**
 * 士只能走一格斜线
 */
type 士可以去那里吗<
  起始位置 extends 棋子坐标,
  目标位置 extends 棋子坐标
> = 是 extends 相同位置<左邻位<上邻位<起始位置>>, 目标位置>
  ? 是
  : 是 extends 相同位置<右邻位<上邻位<起始位置>>, 目标位置>
  ? 是
  : 是 extends 相同位置<右邻位<下邻位<起始位置>>, 目标位置>
  ? 是
  : 是 extends 相同位置<左邻位<下邻位<起始位置>>, 目标位置>
  ? 是
  : 否

/**
 * 象需要遍历四个斜向“田”的位置，并且判断象眼
 */
type 象可以去那里吗<
  起始位置 extends 棋子坐标,
  目标位置 extends 棋子坐标,
  当前棋局 extends 棋局
> = 是 extends 相同位置<左邻位<左邻位<上邻位<上邻位<起始位置>>>>, 目标位置> // 左上
  ? 是 extends 该位置没有棋子<当前棋局, 左邻位<上邻位<起始位置>>> // 象眼
    ? 是
    : 否
  : 是 extends 相同位置<右邻位<右邻位<上邻位<上邻位<起始位置>>>>, 目标位置> // 右上
  ? 是 extends 该位置没有棋子<当前棋局, 右邻位<上邻位<起始位置>>> // 象眼
    ? 是
    : 否
  : 是 extends 相同位置<右邻位<右邻位<下邻位<下邻位<起始位置>>>>, 目标位置> // 右下
  ? 是 extends 该位置没有棋子<当前棋局, 右邻位<下邻位<起始位置>>> // 象眼
    ? 是
    : 否
  : 是 extends 相同位置<左邻位<左邻位<下邻位<下邻位<起始位置>>>>, 目标位置> // 左下
  ? 是 extends 该位置没有棋子<当前棋局, 左邻位<下邻位<起始位置>>> // 象眼
    ? 是
    : 否
  : 否

/**
 * 马需要遍历八个斜向“日”字的位置，并且判断马腿
 */
type 马可以去那里吗<
  起始位置 extends 棋子坐标,
  目标位置 extends 棋子坐标,
  当前棋局 extends 棋局
> = 是 extends 相同位置<左邻位<左邻位<上邻位<起始位置>>>, 目标位置> // 上偏左
  ? 是 extends 该位置没有棋子<当前棋局, 左邻位<起始位置>> // 马腿在起始位置正左一位
    ? 是
    : 否
  : 是 extends 相同位置<左邻位<上邻位<上邻位<起始位置>>>, 目标位置> // 左偏上
  ? 是 extends 该位置没有棋子<当前棋局, 上邻位<起始位置>> // 马腿在起始位置正上一位
    ? 是
    : 否
  : 是 extends 相同位置<右邻位<上邻位<上邻位<起始位置>>>, 目标位置> // 右偏上
  ? 是 extends 该位置没有棋子<当前棋局, 上邻位<起始位置>> // 马腿在起始位置正上一位
    ? 是
    : 否
  : 是 extends 相同位置<右邻位<右邻位<上邻位<起始位置>>>, 目标位置> // 上偏右
  ? 是 extends 该位置没有棋子<当前棋局, 右邻位<起始位置>> // 马腿在起始位置正右一位
    ? 是
    : 否
  : 是 extends 相同位置<右邻位<右邻位<下邻位<起始位置>>>, 目标位置> // 下偏右
  ? 是 extends 该位置没有棋子<当前棋局, 右邻位<起始位置>> // 马腿在起始位置正右一位
    ? 是
    : 否
  : 是 extends 相同位置<右邻位<下邻位<下邻位<起始位置>>>, 目标位置> // 右偏下
  ? 是 extends 该位置没有棋子<当前棋局, 下邻位<起始位置>> // 马腿在起始位置正下一位
    ? 是
    : 否
  : 是 extends 相同位置<左邻位<下邻位<下邻位<起始位置>>>, 目标位置> // 左偏下
  ? 是 extends 该位置没有棋子<当前棋局, 下邻位<起始位置>> // 马腿在起始位置正下一位
    ? 是
    : 否
  : 是 extends 相同位置<左邻位<左邻位<下邻位<起始位置>>>, 目标位置> // 下偏左
  ? 是 extends 该位置没有棋子<当前棋局, 左邻位<起始位置>> // 马腿在起始位置正左一位
    ? 是
    : 否
  : 否

/**
 * 车，直线无阻挡
 */
type 车可以去那里吗<
  起始位置 extends 棋子坐标,
  目标位置 extends 棋子坐标,
  当前棋局 extends 棋局
> = 在一条直线上并且中间没有棋子<起始位置, 目标位置, 当前棋局>

/**
 * 炮，直线无阻挡，或者直线上隔一个
 */
type 炮可以去那里吗<
  起始位置 extends 棋子坐标,
  目标位置 extends 棋子坐标,
  当前棋局 extends 棋局
> = 是 extends 在一条直线上并且中间没有棋子<起始位置, 目标位置, 当前棋局>
  ? 是
  : 是 extends 在一条直线上并且中间只有一个棋子<起始位置, 目标位置, 当前棋局> &
      该位置有棋子<当前棋局, 目标位置>
  ? 是
  : 否

/**
 * 兵只能前进或者左右：
 * - 红兵的前进是向上
 * - 黑兵的前进是向下
 */
type 兵可以去那里吗<
  某个兵 extends 棋子,
  起始位置 extends 棋子坐标,
  目标位置 extends 棋子坐标
> = 是 extends 相同位置<左邻位<起始位置>, 目标位置>
  ? 是
  : 是 extends 相同位置<右邻位<起始位置>, 目标位置>
  ? 是
  : 某个兵['颜色'] extends 红色
  ? 是 extends 相同位置<上邻位<起始位置>, 目标位置>
    ? 是
    : 否
  : 是 extends 相同位置<下邻位<起始位置>, 目标位置>
  ? 是
  : 否

type 具体的某个棋子可以从这里走到那里吗<
  某个棋子 extends 棋子,
  起始位置 extends 棋子坐标,
  目标位置 extends 棋子坐标,
  当前棋局 extends 棋局
> = 某个棋子['种类'] extends 将
  ? 将可以去那里吗<起始位置, 目标位置>
  : 某个棋子['种类'] extends 士
  ? 士可以去那里吗<起始位置, 目标位置>
  : 某个棋子['种类'] extends 象
  ? 象可以去那里吗<起始位置, 目标位置, 当前棋局>
  : 某个棋子['种类'] extends 马
  ? 马可以去那里吗<起始位置, 目标位置, 当前棋局>
  : 某个棋子['种类'] extends 车
  ? 车可以去那里吗<起始位置, 目标位置, 当前棋局>
  : 某个棋子['种类'] extends 炮
  ? 炮可以去那里吗<起始位置, 目标位置, 当前棋局>
  : 兵可以去那里吗<某个棋子, 起始位置, 目标位置>

/**
 * 首先判断能否出现在目标位置
 * 再判断目标位置有没有己方棋子
 * 如果是敌方，或者是空的，就判断能不能走过去
 */
type 棋子可以从这里走到那里吗<
  起始位置 extends 棋子坐标,
  目标位置 extends 棋子坐标,
  当前棋局 extends 棋局
> = 获取棋局某位置的棋子<当前棋局, 起始位置> extends infer 待移动的棋子
  ? 待移动的棋子 extends 棋子
    ? 是 extends 棋子可以放在这里吗<待移动的棋子, 目标位置>
      ? 获取棋局某位置的棋子<当前棋局, 目标位置> extends infer 目标位置棋子
        ? 目标位置棋子 extends 棋子
          ? 目标位置棋子['颜色'] extends 待移动的棋子['颜色'] // 已经有棋子的话，颜色跟自己的一样是不能走的
            ? 否
            : 具体的某个棋子可以从这里走到那里吗<
                待移动的棋子,
                起始位置,
                目标位置,
                当前棋局
              > // 吃对方
          : 具体的某个棋子可以从这里走到那里吗<
              待移动的棋子,
              起始位置,
              目标位置,
              当前棋局
            > // 走到空位置
        : 否
      : 不可能
    : 否
  : 不可能

export type 走棋<
  当前棋局 extends 棋局,
  起始位置 extends 棋子坐标,
  目标位置 extends 棋子坐标
> = 获取棋局某位置的棋子<当前棋局, 起始位置> extends infer 待移动的棋子
  ? 待移动的棋子 extends 棋子
    ? 是 extends 棋子可以从这里走到那里吗<起始位置, 目标位置, 当前棋局>
      ? 将棋局某位置替换为指定棋子<
          将棋局某位置替换为指定棋子<当前棋局, 起始位置, 空>,
          目标位置,
          待移动的棋子
        >
      : 不可能
    : 不可能
  : 不可能

// TODO 后面改造一个这种入口，来自引证的建议
// type 移动<动作> = 动作 extends infer `${红棋}${坐标}${方向}${数字}` ? ...
// 移动<"炮二平五">

/**
 * 测试代码
 */

type 将的移动0 = 将可以去那里吗<构造棋子坐标<三, 三>, 构造棋子坐标<四, 三>>
type 将的移动1 = 将可以去那里吗<构造棋子坐标<三, 三>, 构造棋子坐标<二, 三>>
type 将的移动2 = 将可以去那里吗<构造棋子坐标<三, 三>, 构造棋子坐标<三, 四>>
type 将的移动3 = 将可以去那里吗<构造棋子坐标<三, 三>, 构造棋子坐标<四, 四>>

type 士的移动0 = 士可以去那里吗<构造棋子坐标<三, 三>, 构造棋子坐标<四, 三>>
type 士的移动1 = 士可以去那里吗<构造棋子坐标<三, 三>, 构造棋子坐标<二, 四>>
type 士的移动2 = 士可以去那里吗<构造棋子坐标<三, 三>, 构造棋子坐标<三, 四>>
type 士的移动3 = 士可以去那里吗<构造棋子坐标<三, 三>, 构造棋子坐标<四, 四>>

type 象的移动0 = 象可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<四, 五>,
  默认棋局
>
type 象的移动1 = 象可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<二, 一>,
  默认棋局
>
type 象的移动2 = 象可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<五, 五>,
  默认棋局
>
type 象的移动3 = 象可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<一, 五>,
  默认棋局
>

type 马的移动0 = 马可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<四, 五>,
  默认棋局
>
type 马的移动1 = 马可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<二, 一>,
  默认棋局
>
type 马的移动2 = 马可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<二, 四>,
  默认棋局
>
type 马的移动3 = 马可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<二, 二>,
  默认棋局
>

type 车的移动0 = 车可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<三, 五>,
  默认棋局
>
type 车的移动1 = 车可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<七, 三>,
  默认棋局
>
type 车的移动2 = 车可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<二, 四>,
  默认棋局
>
type 车的移动3 = 车可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<四, 四>,
  默认棋局
>

type 炮的移动0 = 炮可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<三, 五>,
  默认棋局
>
type 炮的移动1 = 炮可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<六, 三>,
  默认棋局
>
type 炮的移动2 = 炮可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<二, 四>,
  默认棋局
>
type 炮的移动3 = 炮可以去那里吗<
  构造棋子坐标<三, 三>,
  构造棋子坐标<四, 四>,
  默认棋局
>

type 兵的移动0 = 兵可以去那里吗<
  构造棋子<红色, 兵>,
  构造棋子坐标<三, 三>,
  构造棋子坐标<三, 四>
>
type 兵的移动1 = 兵可以去那里吗<
  构造棋子<红色, 兵>,
  构造棋子坐标<三, 三>,
  构造棋子坐标<三, 二>
>
type 兵的移动2 = 兵可以去那里吗<
  构造棋子<黑色, 兵>,
  构造棋子坐标<三, 三>,
  构造棋子坐标<二, 三>
>
type 兵的移动3 = 兵可以去那里吗<
  构造棋子<黑色, 兵>,
  构造棋子坐标<三, 三>,
  构造棋子坐标<四, 三>
>

/**
 * 选中+移动的集成测试
 */
type 位置10的马能不能走到22 = 棋子可以从这里走到那里吗<
  构造棋子坐标<一, 零>,
  构造棋子坐标<二, 二>,
  默认棋局
>

type 位置10的马能不能走到31 = 棋子可以从这里走到那里吗<
  构造棋子坐标<一, 零>,
  构造棋子坐标<三, 一>,
  默认棋局
>

type 位置00的车能不能走到01 = 棋子可以从这里走到那里吗<
  构造棋子坐标<零, 零>,
  构造棋子坐标<零, 一>,
  默认棋局
>

// tslint: disable-next-line
type 位置00的车能不能走到07 = 棋子可以从这里走到那里吗<
  构造棋子坐标<零, 零>,
  构造棋子坐标<零, 七>,
  默认棋局
>

type 位置00的车能不能走到11 = 棋子可以从这里走到那里吗<
  构造棋子坐标<零, 零>,
  构造棋子坐标<一, 一>,
  默认棋局
>

type 位置00的车能不能走到70 = 棋子可以从这里走到那里吗<
  构造棋子坐标<零, 零>,
  构造棋子坐标<七, 零>,
  默认棋局
>

type 位置12的炮能不能走到22 = 棋子可以从这里走到那里吗<
  构造棋子坐标<一, 二>,
  构造棋子坐标<二, 二>,
  默认棋局
>

type 位置12的炮能不能走到19 = 棋子可以从这里走到那里吗<
  构造棋子坐标<一, 二>,
  构造棋子坐标<一, 九>,
  默认棋局
>

// 走棋的测试
type 移动棋子0 = 将棋局某位置替换为指定棋子<
  默认棋局,
  构造棋子坐标<零, 零>,
  构造棋子<红色, 车>
>
type 走棋结果0 = 渲染棋局<移动棋子0>
